#include "util.h"
bool comparator_term(const termpair& l, const termpair& r)
{
        return l.second > r.second;
}


/*
 * 将字符串打散到数组中
 */
int explode(std::string str, std::string delimiter, std::vector<std::string> &store)
{
    int strlen = str.length();
    int dellen = delimiter.length();
    if (dellen==0 || strlen == 0) {
        return -1;//no change
    }
    int i=0; 
    int k=0;
    while( i<strlen ) {
        int j=0;
        while (i+j<strlen && j<dellen && str[i+j]==delimiter[j])
            j++;
        if (j==dellen){ //found delimiter 
            store.push_back(str.substr(k, i-k));
            i+=dellen;
            k=i;
        } else {
            i++;
        }
    }
    store.push_back(str.substr(k, i-k));
    return store.size(); }

/**
 * 打印一个vector
 */
template<typename T>
void print(vector<T> &arr)
{
    size_t length = arr.size();
    for (size_t i = 0; i != length; ++i) {
        std::cout << arr.at(i) << '\n';
    }
}

/*
 * 加载一个id映射文件到vector中，输入变量包括文件名，存储的vector
 * 输入文件的格式如下：
 * id1 id2
 * id2 id4
 * id3 id4
 */
int loadIntVector(const char* filename, vector<int> &vec)
{
    //std::cout << filename << endl;
    char rateStr[100];
    char* pch;
    std::ifstream from;
    from.open(filename);
    if (!from.is_open()) {
        cout << "can't open input file:" << filename << "!\n";
        exit(1);
    }   
    int itemId = 1, linkNum = 0, itemNum = 0;
    while (from.getline(rateStr, 100)) {
        if (strlen(rateStr) < 3)continue;
        pch = strtok (rateStr, " ");
        if (pch != NULL) {
            itemId = atoi(pch);
        }
        pch = strtok (NULL, " ");
        linkNum = atoi(pch);
        vec[itemId] = linkNum;
        ++itemNum;
    }
    cout << itemNum << '\t' << linkNum << endl;
    from.close();
    return itemNum;
}

/*
 * 加载类别集合到vector数组中，输入变量包括文件名，存储的vector array
 * 文件的格式如下：
 * id1 id2,id3,id5
 * id2 id4,id1
 * id3 id9,id8
 */
int loadIntVectorArray(const char* filename, vector< vector<int> > &vecArray,
        int maxSetNum)
{
    char rateStr[270000];
    char* pch;
    std::ifstream from (filename);
    if (!from.is_open()) {
        cout << "can't open input file:" << filename << "!\n";
        exit(1);
    }   
    int itemId = 1, itemNum = 0;
    int relatedId = 0;
    while(from.getline(rateStr,270000)){
        if (strlen(rateStr) < 3)continue;
        pch = strtok (rateStr, " ");
        if (pch != NULL) {
            itemId = atoi(pch);
        }
        pch = strtok (NULL, ",");
        int i = 0;
        while (pch != NULL) {
            relatedId = atoi(pch);
            //cout << relatedId << endl;
            vecArray[itemId].push_back(relatedId);
            ++i;
            if (maxSetNum != -1 && i >= maxSetNum) break;
            pch = strtok (NULL, ",");
        }
        ++itemNum;
        //cout<< "Read set " << itemId << endl;
    }
    from.close();
    return itemNum;
}

bool isSampledQuestionId(int qId)
{
    if (qId % 20 < 4) return true;
    else return false;
}

/**
 *  
 * 从mongo数据库中通过bool查询获得包含terms中所有term的问题集合
 */
void getBoolSearchRet(const std::vector<int> &terms, std::vector<int> &ret, 
        const std::string mongodbCollection, const std::string host) {
    ret.clear();
    mongo::DBClientConnection c;
    mongo::BSONObj p;
    c.connect(host);
    mongo::BSONArrayBuilder b;
    std::vector<int>::const_iterator it;
    for (it = terms.begin(); it != terms.end(); ++it) {
        b.append(*it);
    }
    mongo::BSONObj filter = BSON("id" << BSON("$in" << b.arr()));
    auto_ptr<mongo::DBClientCursor> cursor = c.query(mongodbCollection, filter);  
    int count = 0;
    //first merge, then unique
    /*
    while (cursor->more()) {  
        count++;  
        mongo::BSONObj obj = cursor->next();  
        std::vector<int> ints;
        obj.getObjectField("relatedDoc").Vals(ints); // asserts on non int values
        if (ints.size() > 30000) continue;
        //cout << "term " << obj.getIntField("id") << " has " << ints.size() << " documents!" << endl;
        std::copy(ints.begin(), ints.end(), std::back_inserter(ret));
    }
    */
    //@todo 先求一次交集，如果得到的结果太少，比如少于30个，再求并集
    while (cursor->more()) {  
        mongo::BSONObj obj = cursor->next();  
        std::vector<int> ints;
        obj.getObjectField("relatedDoc").Vals(ints); // asserts on non int values
        if (ints.size() > 500000) continue;
        count++;  
        //cout << "term " << obj.getIntField("id") << " has " << ints.size() << " documents!" << endl;
        std::copy(ints.begin(), ints.end(), std::back_inserter(ret));
    }
    cout << "has " << count << " terms!" << endl; 
    sort(ret.begin(), ret.end());
    it = unique(ret.begin(), ret.end()); 
    ret.resize(it - ret.begin()); 
}

/**
 *  
 * 从mongo数据库中通过bool查询获得包含terms中所有term的问题集合
 */
void getBoolSearchRet(std::map<int,float> &terms, std::vector<int> &ret, 
        const std::string mongodbCollection, const std::string host) 
{
    std::map<int,float>::iterator it = terms.begin();
    std::map<int,float>::iterator end = terms.end();
    std::vector< termpair > termPair;
    vector<int> termVector;
    for (; it != end; ++it) {
        termPair.push_back(termpair(it->first, it->second));
    }
    std::sort(termPair.begin(), termPair.end(), comparator_term);
    std::vector< std::pair<int, float> >::iterator vecIt = termPair.begin();
    std::vector< std::pair<int, float> >::iterator vecEnd = termPair.end();
    int termCount = 0;
    for (; vecIt != vecEnd; ++vecIt) {
        termCount++;
        if (termCount > 6) break;
        termVector.push_back(vecIt->first);
    }
    //print(termVector);
    getBoolSearchRet(termVector, ret, mongodbCollection, host);
}
